package _0_4_买卖股票

/*
*
原题链接:
https://leetcode.cn/problems/best-time-to-buy-and-sell-stock/

121. 买卖股票的最佳时机
给定一个数组 prices ，它的第 i 个元素 prices[i] 表示一支给定股票第 i 天的价格。

你只能选择 某一天 买入这只股票，并选择在 未来的某一个不同的日子 卖出该股票。
设计一个算法来计算你所能获取的最大利润。
返回你可以从这笔交易中获取的最大利润。如果你不能获取任何利润，返回 0 。

示例 1：
输入：[7,1,5,3,6,4]
输出：5
解释：在第 2 天（股票价格 = 1）的时候买入，在第 5 天（股票价格 = 6）的时候卖出，
最大利润 = 6-1 = 5 。
注意利润不能是 7-1 = 6, 因为卖出价格需要大于买入价格；同时，你不能在买入前卖出股票。

示例 2：
输入：prices = [7,6,4,3,1]
输出：0
解释：在这种情况下, 没有交易完成, 所以最大利润为 0。

思路:
一. dp数组含义
  - dp[i][0]: 第i天持有股票的状态, 持有的现金数
    dp[i][1]: 第i天不持有股票的状态, 持有的现金数

二. 递推公式

  - 如果第i天持有股票dp[i][0], 那么可以由两个状态推出来

  - 第i-1天就持有股票，那么就保持现状，所得现金就是昨天持有股票的所得现金
    即： dp[i-1][0]

  - 第i天买入股票， 所得现金就是买入今天的股票后所得现金即: -prices[i]

  - 那么dp[i][0]应该选所得现金最大的，所以dp[i][0] = max(dp[i-1][0], -prices[i])

  - 同理dp[i][1]取最大的，dp[i][1] = max(dp[i-1][1], prices[i] + dp[i-1][0])
    这样递推公式就分析完了

三. 初始化

	由递推公式: dp[i][0] = max(dp[i-1][0], -prices[i])
			  dp[i][1] = max(dp[i-1][1], prices[i] + dp[i-1][0])

其基础都是要从dp[0][0]和dp[0][1]推导出来的

那么dp[0][0]表示第0天持有股票， 此时的持有股票就一定是买入股票了
dp[0][0] = -prices[0]
dp[0][1]表示第0天不持有股票，不持有股票那么现金就是0，所以dp[0][1] = 0

四. 遍历顺序

	由于dp[i]都是从dp[i-1]推导出来的， 那么一定是从前向后遍历
	最终返回dp[i][1]即可，因为不持有股票肯定比持有股票的现金数更多

五. 打印dp数组
*/
func maxProfit(prices []int) int {
	n := len(prices)
	dp := make([][]int, n) //dp[i][0]:第i天持有股票 现金数 dp[i][1]:第i天不持有股票 现金数
	for i := range dp {
		dp[i] = make([]int, 2)
	}

	dp[0][0] = -prices[0] // 初始化第0天, 持有股票
	dp[0][1] = 0          //第0天, 不持有股票

	for i := 1; i < n; i++ {
		dp[i][0] = max(dp[i-1][0], -prices[i])           //第i天持有股票, 可能是昨天就持有了, 可能是今天刚刚买入
		dp[i][1] = max(dp[i-1][1], dp[i-1][0]+prices[i]) //第i天不持有股票, 可能昨天就不持有, 可能是今天刚刚卖出
	}

	return dp[n-1][1] //返回第n天,不持有股票所得利润数
}

func max(a int, b int) int {
	if a > b {
		return a
	}

	return b
}
